package level.editor.control.tile;


import utility.ImageUtility;

import java.awt.BorderLayout;
import java.awt.Cursor;
import java.awt.FlowLayout;
import java.awt.Graphics2D;
import java.awt.Image;
import java.awt.Point;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.KeyEvent;
import java.awt.event.MouseEvent;
import java.awt.event.WindowEvent;
import java.awt.event.WindowFocusListener;
import java.awt.image.BufferedImage;

import javax.swing.ImageIcon;
import javax.swing.JPanel;
import javax.swing.SwingUtilities;


import level.editor.control.Handler;
import level.editor.control.layer.Layer;
import level.editor.control.main.Main;
import level.model.Tile;

public class TileHandler extends Handler implements ActionListener,
		WindowFocusListener
{
	public TileHandler(TileControl control)
	{
		super();
		this.control = control;
		selectedButton = null;
		buffer = null;
		type = TYPE_SINGLE;
		control.addKeyListener(this);
	}

	public void createTileSelect(String string)
	{
		BorderLayout layout = (BorderLayout) control.getLayout();
		JPanel panel;

		if (layout.getLayoutComponent(BorderLayout.CENTER) != null)
		{
			panel = (JPanel) layout.getLayoutComponent(BorderLayout.CENTER);
			panel.removeAll();
		}
		
		else
			panel = new JPanel(new FlowLayout(FlowLayout.LEADING, 0, 0));

		Image icon = new ImageIcon(string).getImage();
		int cols = (int) (icon.getWidth(null) / TileConstants.TILE_SIZE);
		int rows = (int) (icon.getHeight(null) / TileConstants.TILE_SIZE);
		BufferedImage images[] = ImageUtility.splitImage(
				ImageUtility.toBufferedImage(icon), cols, rows);

		if (images != null)
		{
			for (int i = 0; i < images.length; i++)
			{
				TileButton button = new TileButton(new ImageIcon(images[i]));
				button.setIconPath(string);
				button.setSx((int) ImageUtility.extractPoint(cols, rows, i,
						(int) TileConstants.TILE_SIZE).x);
				button.setSy((int) ImageUtility.extractPoint(cols, rows, i,
						(int) TileConstants.TILE_SIZE).y);
				button.addActionListener(this);
				panel.add(button);
			}
		}

		control.add(panel, BorderLayout.CENTER);
		control.revalidate();
	}

	@Override
	public void finish()
	{
		// TODO Auto-generated method stub

	}

	@Override
	public void mousePressed(MouseEvent e)
	{
		if (SwingUtilities.isLeftMouseButton(e) && selectedButton != null
				&& e.getSource() instanceof Main)
		{
			Main main = (Main) e.getSource();
			main.requestFocusInWindow();
			// Add custom cursor later
			Tile tile = selectedButton.getTile();
			if (main.getSelectedLayer() != null
					&& !main.getSelectedLayer().isLocked()
					&& main.getCollisionLayer().isVisible()
					&& type == TYPE_SINGLE)
			{
				Layer layer = main.getSelectedLayer();
				Point point = snapPoint(main.getOrigin(), e.getPoint());

				tile.setX((int) point.getX());
				tile.setY((int) point.getY());

				layer.addObject(tile);
				main.setDirty(Main.DIRTY);
				main.createMemento();
				((TileLayer) layer).requestMinimap();
				layer.repaint();
			}

			else if (main.getSelectedLayer() != null
					&& !main.getSelectedLayer().isLocked()
					&& main.getCollisionLayer().isVisible()
					&& type == TYPE_RECTANGLE)
			{
				if (buffer == null)
				{
					// Change to custom cursor here
					main.setCursor(new Cursor(Cursor.MOVE_CURSOR));
					Layer layer = main.getSelectedLayer();
					buffer = newLayerBuffer(main, layer,
							snapPoint(main.getOrigin(), e.getPoint()),
							tile.cloneTile());
					main.minimapUpdate();
				}
			}
		}
	}

	@Override
	public void mouseDragged(MouseEvent e)
	{
		if (SwingUtilities.isLeftMouseButton(e) && selectedButton != null
				&& e.getSource() instanceof Main)
		{
			Main main = (Main) e.getSource();
			main.requestFocusInWindow();
			if (main.getSelectedLayer() != null
					&& !main.getSelectedLayer().isLocked()
					&& main.getCollisionLayer().isVisible()
					&& type == TYPE_RECTANGLE)
			{
				if (buffer != null)
				{
					buffer.repaint();
					buffer.setEndPoint(snapPoint(main.getOrigin(), e.getPoint()));
					// main.minimapUpdate();
					// WHY DOES THIS REPAINT SO WELL!?!?
					// OH GOD GLORIOUS
				}
			}
		}
	}

	@Override
	public void mouseMoved(MouseEvent e)
	{
		if (selectedButton != null && e.getSource() instanceof Main)
		{
			Main main = (Main) e.getSource();
			main.requestFocusInWindow();
			if (main.getSelectedLayer() != null
					&& !main.getSelectedLayer().isLocked()
					&& main.getSelectedLayer().isVisible())
			{
				if (buffer == null)
				{
					Layer layer = main.getSelectedLayer();
					Tile tile = selectedButton.getTile();
					Point point = snapPoint(main.getOrigin(), e.getPoint());

					tile.setX((int) point.getX());
					tile.setY((int) point.getY());

					layer.setGhost(tile, selectedButton.getIcon());

					((TileLayer) layer).requestMinimap();
					layer.repaint();
				}
			}
		}
	}

	@Override
	public void mouseReleased(MouseEvent e)
	{
		if (SwingUtilities.isLeftMouseButton(e) && selectedButton != null
				&& e.getSource() instanceof Main)
		{
			Main main = (Main) e.getSource();
			main.requestFocusInWindow();
			main.setCursor(new Cursor(Cursor.DEFAULT_CURSOR));
			if (main.getSelectedLayer() != null
					&& !main.getSelectedLayer().isLocked()
					&& main.getCollisionLayer().isVisible()
					&& type == TYPE_RECTANGLE)
			{
				if (buffer != null)
				{
					Layer layer = main.getSelectedLayer();
					// buffer.setEndPoint(snapPoint(main.getOrigin(),
					// e.getPoint()));
					buffer.finishRectangle(layer);
					main.minimapUpdate();
					type = TYPE_SINGLE;
					buffer = null;
				}
			}
		}
	}

	@Override
	public void paint(Graphics2D g, Point topLeft)
	{
		String tileString = "Tile:   ";
		g.drawString(tileString, (int) topLeft.getX(), (int) topLeft.getY());
		if (selectedButton != null)
		{
			g.drawImage(((ImageIcon) selectedButton.getIcon()).getImage(),
					(int) (topLeft.getX() + TOOL_X_OFFSET),
					(int) (topLeft.getY() + TOOL_Y_OFFSET), null);
		}
		String typeString = "Type:  ";

		typeString += type;
		g.drawString(typeString, (int) topLeft.getX(),
				(int) (topLeft.getY() + TYPE_Y_OFFSET));
	}

	@Override
	public void actionPerformed(ActionEvent e)
	{
		if (e.getSource() instanceof TileButton)
		{
			control.registerHandler();
			if (selectedButton != null)
				selectedButton.selected(false);
			selectedButton = (TileButton) e.getSource();
			selectedButton.selected(true);
			control.requestFocusInWindow();
			control.getMain().repaint();
		}
	}

	@Override
	public void keyPressed(KeyEvent e)
	{
		if (e.getKeyCode() == KeyEvent.VK_CONTROL)
		{
			type = TYPE_RECTANGLE;
			control.getMain().repaint();
		}
	}

	@Override
	public void keyReleased(KeyEvent e)
	{
		if (e.getKeyCode() == KeyEvent.VK_CONTROL)
		{
			if (buffer == null)
				type = TYPE_SINGLE;

			if (buffer != null)
				buffer.repaint();

			control.getMain().repaint();
		}
	}

	@Override
	public void windowGainedFocus(WindowEvent e)
	{
		// TODO Auto-generated method stub
	}

	@Override
	public void windowLostFocus(WindowEvent e)
	{
		type = TYPE_SINGLE;
		if (control.getMain() != null)
			control.getMain().repaint();
	}

	private TileBuffer newLayerBuffer(Main main, Layer layer, Point point,
			Tile tile)
	{
		TileBuffer buffer = new TileBuffer(layer.getLayerNumber(), point, tile,
				main);
		return buffer;
	}

	private Point snapPoint(Point origin, Point initialPoint)
	{
		Point point = new Point();
		point.x = (int) (initialPoint.getX() - origin.getX());
		point.y = (int) (initialPoint.getY() - origin.getY());

		point.x = point.x - (point.x < 0 ? TileConstants.TILE_SIZE : 0);
		point.y = point.y - (point.y < 0 ? TileConstants.TILE_SIZE : 0);

		point.x = point.x - point.x % TileConstants.TILE_SIZE;
		point.y = point.y - point.y % TileConstants.TILE_SIZE;

		return point;
	}

	private TileControl control;
	private TileButton selectedButton;
	private String type;
	private TileBuffer buffer;
	private static final int TOOL_X_OFFSET = 50;
	private static final int TOOL_Y_OFFSET = -20;
	private static final int TYPE_Y_OFFSET = 50;
	private static final String TYPE_SINGLE = "Single";
	private static final String TYPE_RECTANGLE = "Drag Rectangle";
}
